package edu.corn.job.core.context;

import lombok.AllArgsConstructor;
import lombok.Data;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Stack;
import java.util.concurrent.atomic.AtomicInteger;

/**
 *
 */
public class ContextCommandManager implements Serializable {

    @Data
    @AllArgsConstructor
    public static final class ContextCommand {

        // 本次放入的key
        private String key;

        // 本次放入的value
        private Serializable value;

        // 本次放入之前的value，可能存在，新增为null，更改为值
        private Serializable beforeValue;

        // 本次操作的版本号
        private Integer version;
    }

    // 存储命令的栈
    Stack<ContextCommand> contextCommandStack = new Stack<ContextCommand>();

    // 版本号计数器，线程安全
    private final AtomicInteger versionCounter = new AtomicInteger(0);

    /**
     * 保存信息的上下文map。
     */
    private final transient HashMap<String, Serializable> context = new HashMap<>();

    /**
     * 幂等，不备份。
     * @param key 键。
     * @return Object
     */
    public Object getParam(String key) {
        return context.get(key);
    }


    public <T extends Serializable> Integer putParam(String key, T value) {
        // 获取当前值，可能为 null
        Serializable beforeValue = context.get(key);

        // 将新值放入上下文
        context.put(key, value);

        // 获取当前版本号并自增
        int version = versionCounter.incrementAndGet();

        // 构造ContextCommand
        ContextCommand command = new ContextCommand(key, value, beforeValue, version);

        // 将命令放入栈中
        contextCommandStack.push(command);

        return version;
    }

    /**
     * 根据版本号回滚到指定版本。
     * @param version 需要回滚到的版本号
     */
    public void rollbackToVersion(int version) {
        // 不断从栈中弹出操作，直到找到指定版本
        while (!contextCommandStack.isEmpty()) {
            ContextCommand command = contextCommandStack.peek(); // 取出栈顶元素但不弹出
            if (command.getVersion() > version) {
                // 如果当前命令版本大于目标版本，则执行回滚
                contextCommandStack.pop(); // 弹出栈顶元素
                if (command.getBeforeValue() == null) {
                    // 如果beforeValue是null，说明是新增操作，执行删除
                    context.remove(command.getKey());
                } else {
                    // 否则恢复之前的值
                    context.put(command.getKey(), command.getBeforeValue());
                }
            } else {
                // 如果当前命令版本小于或等于目标版本，停止回滚
                break;
            }
        }
    }
}
